<template>
  <el-select
    v-model="model"
    :remote="remote"
    reserve-keyword
    filterable
    :disabled="disabled"
    clearable
    placeholder="请输入关键词"
    :remote-method="remoteQuery"
    @focus="focus"
    :loading="loading">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.text"
      :value="item.value">
    </el-option>
  </el-select>
</template>
<script>
import {dotData, alert} from '@/utils'
import L from 'lodash'
import Emitter from '@/utils/emitter.js'

export default {
  mixins: [Emitter],
  props: {
    url: { // 远程地址 可在config中配置， 此处配置了已此处为准
      type: String,
      default: ''
    },
    config: { // 配置项
      type: Object,
      default() {
        return {}
      }
    },
    getParams: {
      type: [Function, Boolean],
      default: false
    },
    value: {
      type: [String, Number],
      default: ''
    },
    initOptions: { // 初始选中值
      type: Array,
      default() {
        return []
      }
    },
    disabled: {
      type: Boolean,
      default: false
    },
    remote: { // 如果传入false 则代表在 直接获取全部
      type: Boolean,
      default: true
    },
    beforeRequest: {
      type: [Boolean, Function],
      default: false
    }
  },
  data() {
    return {
      options: [],
      innerInitOptions: this.initOptions,
      loading: false,
      model: '',
      itemMap: new Map(),
      firstFocus: false
    }
  },
  created() {
    if (Array.isArray(this.initOptions)) {
      this.options = this.innerInitOptions
    }
    if (this.value) {
      this.model = this.value
    }
  },
  watch: {
    model(val, oldVal) {
      if (val === oldVal || this.value === val) {
        return
      }
      this.$emit('input', val)
      // 抛出整个对象
      if (this.itemMap && this.itemMap.has(val)) {
        this.$emit('update:item', this.itemMap.get(val))
        this.$emit('setItem', this.itemMap.get(val))
      }
      this.$nextTick(_ => {
        this.dispatch('ElFormItem', 'el.form.change', val)
      })
    },
    initOptions(val, oldVal) {
      if (val === oldVal) {
        return
      }
      this.innerInitOptions = val
      this.options = this.handleResponse()
    },
    value(val, oldVal) {
      if (val === oldVal) {
        return
      }
      this.model = val
    }
  },
  destroyed() {
    this.itemMap = null
  },
  methods: {
    // 远程搜索
    remoteMethod: L.debounce((query, _this) => {
      _this.handleRequest(query)
    }, 1000),
    // 发起异步请求
    handleRequest(query = '') {
      if (L.isFunction(this.beforeRequest)) {
        if (!this.beforeRequest()) {
          return
        }
      }
      let url = this.url || this.config.url
      if (url) {
        this.loading = true
        this.$ajax.get(url, this.handleParams(query)).then(response => {
          this.options = this.handleResponse(response)
          this.$emit('setOptions', this.options)
        }).finally(_ => {
          this.loading = false
        })
      } else {
        alert('远程地址未定义')
      }
    },
    remoteQuery(query) {
      this.remoteMethod(query, this)
    },
    // 处理请求参数
    handleParams(query) {
      if (L.isFunction(this.getParams)) {
        return this.getParams(query)
      } else {
        let temp = {}
        const searchKey = this.config.searchKey || 'name'
        temp[searchKey] = query
        return temp
      }
    },
    // 处理请求回来的数据
    handleResponse(response) {
      const success = dotData(response, 'success')
      let tempArr = []
      if (success) {
        let data = dotData(response, 'data')
        const textKey = this.config.text || 'text'
        const valueKey = this.config.value || 'value'
        if (Array.isArray(data)) {
          this.itemMap = new Map()
          data.forEach((v, k) => {
            this.itemMap.set(v[valueKey], v)
            tempArr.push({
              text: v[textKey],
              value: v[valueKey]
            })
          })
        }
      }
      // 如果有初始化的参数且是第一次请求
      if (Array.isArray(this.initOptions) && this.initOptions.length && !this.remote) {
        tempArr = L.unionBy(tempArr, this.innerInitOptions, 'value')
        this.innerInitOptions = []
      }
      return tempArr
    },
    // 全局请求
    focus(event) {
      // 如果是全部检索则拉取一次(有且只有一次)
      if (!this.firstFocus) {
        this.firstFocus = true
        this.handleRequest()
      }
    },
    // 清空选项，方便重新获取
    clearOptions() {
      this.firstFocus = false
      this.options = []
    }
  }
}
</script>
